package cz.mff.cuni.dpp.liboptions;

import junit.framework.Assert;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Test parsovaní hodnot.
 * 
 */
public class ValueParsingTest {
	private static final Logger logger = LoggerFactory.getLogger(ValueParsingTest.class);

	private static final int INTEGRAL_TEST_LIMITS = 999;

	private String[] testValues = new String[] { "a", "Aba", "bABa", "\tsadXXXasdsa\"", "axa" };

	@Test
	public void parsingVailabilityTest() {

		SwitchOption.Builder booleanBuilder = new SwitchOption.Builder("test");
		Assert.assertFalse(booleanBuilder.buildOption().supportsValue());

		IntegerOption.Builder integerBuilder = new IntegerOption.Builder("test", "N/A");
		Assert.assertTrue(integerBuilder.buildOption().supportsValue());

		StringOption.Builder stringOption = new StringOption.Builder("test", "N/A");
		Assert.assertTrue(stringOption.buildOption().supportsValue());

		EnumOption.Builder enumOption = new EnumOption.Builder("test", "N/A");
		Assert.assertTrue(enumOption.buildOption().supportsValue());

		logger.info("parsingVailabilityTest finihsed");
	}

	@Test
	public void booleanParsingTest() {
		SwitchOption.Builder booleanBuilder = new SwitchOption.Builder("test");
		SwitchOption option = booleanBuilder.buildOption();

		try {
			option.parseValue("");
			Assert.fail("Must thow an UnsupportedOperationException");
		} catch (UnsupportedOperationException e) {
			Assert.assertTrue(true);
		} catch (BadValueException e) {
			Assert.fail("Must thow an UnsupportedOperationException");
		}

		logger.info("booleanParsingTest finihsed");
	}

	@Test
	public void integerParsingTest() {
		IntegerOption.Builder integerBuilder = new IntegerOption.Builder("test", "N/A");
		IntegerOption option = integerBuilder.buildOption();

		int output = 0;
		try {
			for (int i = -INTEGRAL_TEST_LIMITS; i < INTEGRAL_TEST_LIMITS; ++i) {
				output = option.parseValue("" + i);
				Assert.assertEquals(i, output);
			}

			Assert.assertTrue("Error in min value",
					Integer.MIN_VALUE == option.parseValue("" + Integer.MIN_VALUE));
			Assert.assertTrue("Error in max value",
					Integer.MAX_VALUE == option.parseValue("" + Integer.MAX_VALUE));

		} catch (Exception e) {
			Assert.fail("FAIL: " + e.getMessage());
		}

		integerBuilder.setLowerBound(-INTEGRAL_TEST_LIMITS);
		integerBuilder.setUpperBound(INTEGRAL_TEST_LIMITS);

		option = integerBuilder.buildOption();

		try {
			for (int i = -INTEGRAL_TEST_LIMITS; i < INTEGRAL_TEST_LIMITS; ++i) {
				output = option.parseValue("" + i);
				Assert.assertEquals(i, output);
			}

		} catch (Exception e) {
			Assert.fail("FAIL: " + e.getMessage());
		}

		String input = "";
		try {
			int i = -INTEGRAL_TEST_LIMITS - 1;
			input = "" + i;
			output = option.parseValue(input);
			Assert.assertEquals(i, output);
			Assert.fail("Must thow an BadValueException");

		} catch (BadValueException e) {
			Assert.assertTrue(e.isOutOfRange());
			Assert.assertEquals(input, e.getStringValue());
		}

		try {

			int i = INTEGRAL_TEST_LIMITS + 1;
			input = "" + i;
			output = option.parseValue(input);
			Assert.assertEquals(i, output);
			Assert.fail("Must thow an BadValueException");
		} catch (BadValueException e) {
			Assert.assertTrue(e.isOutOfRange());
			Assert.assertEquals(input, e.getStringValue());
		}

		logger.info("integerParsingTest finihsed");
	}

	@Test
	public void stringParsingTest() {
		StringOption.Builder stringBuilder = new StringOption.Builder("test", "N/A");
		StringOption option = stringBuilder.buildOption();

		String output = null;
		try {
			for (String value : testValues) {
				output = option.parseValue(value);
				Assert.assertEquals(value, output);

			}
		} catch (Exception e) {
			Assert.fail("FAIL: " + e.getMessage());
		}

		logger.info("stringParsingTest finihsed");
	}

	@Test
	public void enumParsingTest() {
		EnumOption.Builder enumBuilder = new EnumOption.Builder("test", "N/A");
		EnumOption option = enumBuilder.buildOption();

		String output = null;

		for (String value : testValues) {
			try {
				output = option.parseValue(value);
				Assert.assertEquals(value, output);
				Assert.fail("Must thow an BadValueException");
			} catch (BadValueException e) {
				Assert.assertTrue(e.isOutOfRange());
				Assert.assertEquals(value, e.getStringValue());
			}

		}

		enumBuilder.addAllowedValues(testValues);
		enumBuilder.setCaseSensitive(true);
		option = enumBuilder.buildOption();

		for (String value : testValues) {
			String originalValue = value;
			value = value.toUpperCase();
			if (!originalValue.equals(value)) {
				try {
					output = option.parseValue(value);
					Assert.assertEquals(value, output);
					Assert.fail("Must thow an BadValueException");
				} catch (BadValueException e) {
					Assert.assertTrue(e.isOutOfRange());
					Assert.assertEquals(value, e.getStringValue());
				}
			} else {
				try {
					output = option.parseValue(value);
					Assert.assertEquals(value, output);
				} catch (BadValueException e) {
					Assert.fail("Must not trhow an BadValueException");
				}
			}
		}

		for (String value : testValues) {
			String originalValue = value;
			value = value.toLowerCase();
			if (!originalValue.equals(value)) {
				try {
					output = option.parseValue(value);
					Assert.assertEquals(value, output);
					Assert.fail("Must thow an BadValueException original: " + originalValue
							+ " input: " + value);
				} catch (BadValueException e) {
					Assert.assertTrue(e.isOutOfRange());
					Assert.assertEquals(value, e.getStringValue());
				}
			} else {
				try {
					output = option.parseValue(value);
					Assert.assertEquals(value, output);
				} catch (BadValueException e) {
					Assert.fail("Must not trhow an BadValueException");
				}
			}

		}

		enumBuilder.setCaseSensitive(false);
		option = enumBuilder.buildOption();

		for (String value : testValues) {
			// String originalValue = value;
			try {
				value = value.toLowerCase();
				output = option.parseValue(value);
				Assert.assertEquals(value, output);

				value = value.toUpperCase();
				output = option.parseValue(value);
				Assert.assertEquals(value, output);

			} catch (BadValueException e) {
				Assert.fail("Must not trhow an BadValueException");
			}

		}

		logger.info("enumParsingTest finihsed");
	}
}
